﻿Shader "Unlit/katong"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Diffuse ("Color", Color) = (1,1,1,1)
        _Outline ("Outline", Range(0,2)) = 0.1
        _OutlineColor("OutlineColor", Color) = (0,0,0,0)
        _Steps("Steps",Range(1,30)) = 5
        _ToonEffect("ToonEffect", Range(0,1)) = 0.5
        //渐进纹理
        _RamTex("Texture",2D) = "white"{}
        //边缘光
        _RimColor("RimColor", Color) = (1,1,1,1)
        _RimPower("RimPower", Range(0.0001,3)) = 1
        //Xray
        _XRayColor("XRayColor", Color) = (0,0,1,1)
        _XRayPower("XRayPower", Range(0.0001,3)) = 1
        
    }
    SubShader
    {
        Tags {"Queue"="Geometry+1000" "RenderType"="Opaque" }
        LOD 100
        Pass
        {
            Tags{"ForceNoShadowCasting" = "true"}
            //xRay 效果
           //目的是 一个物体挡住人的时候还能画出来 物体和人 如果先画物体再画人
           //说明被挡住的时候才画出来
           Blend SrcAlpha One
           ZWrite Off
           ZTest Greater
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            fixed4 _XRayColor;
            float _XRayPower;
            
            struct v2f
            {
            float4 vertex : SV_POSITION;
            float3 viewDir : TEXCOORD0;
            float3 normal: TEXCOORD1;
            };
            
            v2f vert(appdata_base v)
            {
             v2f o;
             o.vertex = UnityObjectToClipPos(v.vertex);
            // o.worldNormal = UnityObjectToWorldNormal(v.vertex);
            // o.worldPos = mul(unity_ObjectToWorld, v.vertex);
            
            //进行优化 将法线以及视角方向在顶点进行计算 而不是片元
            o.normal = v.normal;
            o.viewDir = ObjSpaceViewDir(v.vertex);
             return o;
            }
            
            fixed4 frag(v2f i):SV_Target
            {
                //float3 normal = normalize(i.worldNormal);
                //float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                float3 normal = normalize(i.normal);
                float3 viewDir = normalize(i.viewDir);
                
                float rim = 1 - dot(normal, viewDir);
                //return _XRayColor * pow(rim,1/_XRayPower);
                return _XRayColor * rim * _XRayPower;
            }
            
            ENDCG
        }
        
        
        Pass
        {
            //绘制描边 我们只用绘制反面 填充一种颜色即可
            //三种 物体坐标 视角坐标 裁剪坐标
            Name "OUTLINE"
            Cull Front
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            float _Outline;
            fixed4 _OutlineColor;
            
            
            struct v2f
            {
                float4 vertex : SV_POSITION;
            };
            
            
            v2f vert(appdata_base v)
            {
                
                v2f o;
                //物体坐标外拓
                //v.vertex.xyz += v.normal * _Outline;
                //o.vertex = UnityObjectToClipPos(v.vertex);
                
                
                //视角控件外拓
                //float4 pos = mul(UNITY_MATRIX_V, mul(unity_ObjectToWorld, v.vertex));
                //MV代表从物体坐标到视角坐标 IT是代表转置 法线的转换是不一样的
               //float3 normal = normalize( mul( (float3x3)UNITY_MATRIX_IT_MV, v.normal));
               // pos = pos + float4(normal,0) * _Outline;
                //下面可以使用 UnityViewToClipPos() 但是参数是float3
               //o.vertex = mul(UNITY_MATRIX_P, pos);
               
               //裁剪空间法线外拓
               //求出裁剪空间的世界坐标
               //转换到视角控件后 法线的z值变成一个纯粹的深度 就是没什么用了
               o.vertex = UnityObjectToClipPos(v.vertex);
               float3 normal = normalize( mul( (float3x3)UNITY_MATRIX_IT_MV, v.normal));
               float2 viewNormal = TransformViewToProjection(normal.xy);
               o.vertex.xy += viewNormal * _Outline;
                return o;
            }
            
            float4 frag(v2f i):SV_Target
            {
                return _OutlineColor;
            }
                       
            ENDCG
        }
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                fixed3 worldNormal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _RamTex;
            float4 _RamTex_ST;
            float4 _Diffuse;
            float _Steps;
            float _ToonEffect;
            fixed4 _RimColor;
            float _RimPower;
            
            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed4 albedo = tex2D(_MainTex, i.uv);
                
                //漫反射
                fixed3 worldLightDir = UnityWorldSpaceLightDir(i.worldPos);
                float difLight = dot(i.worldNormal, worldLightDir)*0.5 + 0.5;
                //卡通的颜色处理 使用色阶smoothstep(min,max,x) x= min 返回0 x= max 返回 1
                //颜色平滑在[0,1]
                difLight = smoothstep(0,1,difLight);
                //颜色离散化
                float toon = floor(difLight * _Steps)/_Steps;
                difLight = lerp(difLight, toon, _ToonEffect);

                //同时也可以使用渐进纹理实现颜色的色阶
                // fixed halfLambert = dot(i.worldNormal, worldLightDir)*0.5 + 0.5;
                // fixed4 rampColor = tex2D(_RampTex, fixed2(halfLambert,halfLambert))
                // fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * rampColor;  
                
                
                //边缘光 当我们视角方向与物体的法线垂直的时候 则为物体的边缘 那么点积为0 边缘cos90
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                float rim = 1 - dot(i.worldNormal, viewDir);
                fixed3 rimColor = _RimColor * pow(rim, 1/_RimPower);
                
                
                fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * difLight;           

                return float4(ambient + diffuse + rimColor, 1);
            }
            ENDCG
        }
    }
     FallBack "Transparent/VertexLit"
}
